#include "ring-buffer.h"

static uint64_t um_addr = UINT64_MAX; // 起始虚拟地址

inline static void *vaddr(uint64_t addr)
{
    return (void *)((uint64_t)addr + um_addr);
}

inline static uint32_t offset(void *addr)
{
    return (uint32_t)((uint64_t)addr - um_addr);
}

static void _memcpy(void *_dst, void const *const _src, size_t size)
{
    TEST_ASSERT_INFO(_dst != NULL, "_dst is NULL\n");
    TEST_ASSERT_INFO(_src != NULL, "_src is NULL\n");
    uint8_t *dst = (uint8_t *)_dst;
    uint8_t const *const src = (uint8_t *)_src;
    for (size_t i = 0; i < size; i++)
    {
        dst[i] = src[i];
    }
}

// static void _memset(void *_addr, uint8_t val, size_t size)
// {
//     uint8_t *addr = (uint8_t *)_addr;
//     for (size_t i = 0; i < size; i++)
//     {
//         addr[i] = val;
//     }
// }

static void __writeData(CircularBuffer *buffer, void const *const data, const size_t dataSize)
{
    size_t spaceToEnd = buffer->buffer_size - buffer->rear; // 从写指针到缓冲区末尾的空间大小

    if (dataSize <= spaceToEnd)
    {
        // 数据可以一次性写入
        _memcpy(vaddr(buffer->data) + buffer->rear, data, dataSize);
    }
    else
    {
        // 数据需要分两次写入
        _memcpy(vaddr(buffer->data) + buffer->rear, data, spaceToEnd);
        _memcpy(vaddr(buffer->data), (char *)data + spaceToEnd, dataSize - spaceToEnd);
    }

    // 因为仅写者使用 rear
    buffer->rear = (buffer->rear + (uint32_t)dataSize) % buffer->buffer_size;
}

bool isEnoughSpace(CircularBuffer *buffer, uint32_t size)
{
    // 单生产者不需要对count加锁
    // 原子读取 count, 消费者可能减小了 count，因此需要原子读取
    uint32_t count = __atomic_load_n(&buffer->count, __ATOMIC_SEQ_CST);
    return count + size <= buffer->buffer_size;
}

// 向环形缓冲区写入数据
uint32_t writeData(CircularBuffer *buffer,
                   op_t *op,
                   void const *const data)
{
    const uint32_t len = (uint32_t)op->param_len + (uint32_t)sizeof(op_t); // 实际需要写入的字节

    // 单生产者不需要对count加锁
    // 原子读取 count, 消费者可能减小了 count，因此需要原子读取
    if (!isEnoughSpace(buffer, len))
    {
        // printf("缓冲区已满，无法写入数据\n");
        return 0;
    }

    // 写入数据头
    __writeData(buffer, op, sizeof(op_t));
    // 写入数据内容
    __writeData(buffer, data, (size_t)op->param_len);

    __sync_synchronize();

    __sync_fetch_and_add(&buffer->count, len);
    atomic_inc(&(buffer->num_call_and_ret));
    return len;
}

/**
 * @brief 从 buffer 中读取数据，如果 data 为 NULL 则直接移动 front 指针，
 * 表示删除数据
 * @param buffer [in] 缓冲区指针
 * @param data [out] 保存读取出的数据指针
 * @param size_2_read [in] 需要读取的数据大小
*/
static void __readData(CircularBuffer *buffer,
                void *data,
                const size_t size_2_read)
{
    TEST_ASSERT_INFO(buffer != NULL, "buffer is NULL\n");
    if (NULL != data)
    { // 读取数据内容
        if (buffer->front + size_2_read <= buffer->buffer_size)
        {
            // 数据可以一次性读取
            _memcpy(data, vaddr(buffer->data) + buffer->front, size_2_read);
        }
        else
        {
            // 数据需要分两次读取
            size_t spaceToEnd = buffer->buffer_size - buffer->front;
            _memcpy(data, vaddr(buffer->data) + buffer->front, spaceToEnd);
            _memcpy((char *)data + spaceToEnd, vaddr(buffer->data), size_2_read - spaceToEnd);
        }
    }

    // 因为仅读者使用 front
    buffer->front = (buffer->front + (uint32_t)size_2_read) % buffer->buffer_size;
}


bool readData(CircularBuffer *buffer,
              op_t *op,
              void *data)
{
    TEST_ASSERT_INFO(buffer != NULL, "buffer is NULL\n");
    TEST_ASSERT_INFO(op != NULL, "op is NULL\n");

    // 读前加内存屏障是为了保证是从内存里面读数据的
    // riscv 指令的内存屏障是可以保证这一点的，其他体系结构似乎不能够使用该方法
    __sync_synchronize();

    // 单消费者不需要对count加锁
    // 原子读取 count, 生产者可能增大了 count，因此需要原子读取
    uint32_t count = __atomic_load_n(&buffer->count, __ATOMIC_SEQ_CST);
    if (count == 0)
    {
        // printf("缓冲区为空，无法读取数据\n");
        return false;
    }

    // 读取数据头
    __readData(buffer, op, sizeof(op_t));

    // 复制数据内容到新的内存中
    __readData(buffer, data, (size_t)op->param_len);

#ifdef TEST_UMMANAGE
    {
        uint32_t size = (uint32_t)op->param_len + (uint32_t)sizeof(op_t);
        TEST_ASSERT_INFO(count >= size, "buffer->count=%d, size=%d\n", count, size);
        TEST_ASSERT_INFO(count <= buffer->buffer_size, "buffer->count=%d, buffer->buffer_size=%d\n", count, buffer->buffer_size);
    }
#endif

    __sync_fetch_and_sub(&buffer->count, (uint32_t)op->param_len + (uint32_t)sizeof(op_t));
    atomic_dec(&(buffer->num_call_and_ret));
    return true;
}

void drop(CircularBuffer *buffer)
{
    op_t op;
    readData(buffer, &op, NULL);
}

// 初始化环形缓冲区
void initCircularBuffer(CircularBuffer *buffer,
                        uint32_t data,
                        uint64_t _um_addr,
                        uint32_t buffer_size)
{
    buffer->data = data;
    buffer->buffer_size = buffer_size;
    buffer->front = 0;
    buffer->rear = 0;
    buffer->count = 0;
    um_addr = _um_addr;
}